package xcmg.device.infra;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Font;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.TableStyle;
import com.alibaba.excel.support.ExcelTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.IndexedColors;
import xcmg.device.infra.exception.CommonBusiExceptions;

import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.ZipOutputStream;

/**
 * 导出Excel公共方法
 *
 * @version 1.0
 */
@Slf4j
public class ExportUtil  {
    private String title;
    private String[] rowName ;
    private List<Object[]> dataList = new ArrayList<>();
    private String[] subTitle;

    public ExportUtil(String title,String[] rowName,List<Object[]>  dataList){
        this.dataList = dataList;
        this.rowName = rowName;
        this.title = title;
        this.subTitle = new String[1];
        this.subTitle[0] = title;
    }

    public ExportUtil(String title, String[] rowName, List<Object[]> dataList, String subTitle) {
        this.dataList = dataList;
        this.rowName = rowName;
        this.title = title;
        this.subTitle = new String[2];
        this.subTitle[0] = title;
        this.subTitle[1] = subTitle;
    }

    public ExportUtil(String title, String[] subTitles, String[] rowName, List<Object[]> dataList) {
        this.dataList = dataList;
        this.rowName = rowName;
        this.title = title;
        this.subTitle = new String[subTitles.length + 1];
        this.subTitle[0] = title;
        for (int i = 1; i < this.subTitle.length; i++) {
            this.subTitle[i] = subTitles[i - 1];
        }
    }

    public void export(ZipOutputStream outputStream) {
        try {
            writeExcelToOutput(outputStream, null, subTitle);
        } catch (Exception e) {
            log.error("", e);
            throw new CommonBusiExceptions(e.getMessage());
        }
    }

    public void export(HttpServletResponse response) {
        try {
            setHttpResponse(response);
            OutputStream outputStream = response.getOutputStream();
            writeExcelToOutput(outputStream, null, subTitle);
        } catch (Exception e) {
            log.error("", e);
            throw new CommonBusiExceptions(e.getMessage());
        }
    }

    public void export(HttpServletResponse response, List<CellMergeParam> cellMergeParams) {
        try {
            setHttpResponse(response);
            OutputStream outputStream = response.getOutputStream();
            writeExcelToOutput1(outputStream, cellMergeParams, subTitle);
        } catch (Exception e) {
            log.error("", e);
            throw new CommonBusiExceptions(e.getMessage());
        }
    }

    public void exportWithoutTitles(HttpServletResponse response, List<CellMergeParam> cellMergeParams)  {
        try {
            setHttpResponse(response);
            OutputStream outputStream = response.getOutputStream();
            writeExcelToOutputWithoutTitles(outputStream, cellMergeParams, subTitle);
        } catch (Exception e) {
            log.error("", e);
            throw new CommonBusiExceptions(e.getMessage());
        }
    }


    private void writeExcelToOutput(OutputStream outputStream, List<CellMergeParam> cellMergeParams, String... titles) {
        List<List<Object>> writeList = new ArrayList<>();
        int index = 1;
        for (Object[] x : dataList) {
            if (x != null) {
                if (x.length > 0) {
                    x[0] = index++;
                }
                writeList.add(Arrays.asList(x));
            }
        }

        doWrite(writeList, outputStream, cellMergeParams, titles);
    }

    /**
     * 原方法将第一列重置为123456...，这里不需要
     * @param outputStream
     * @param cellMergeParams
     * @param titles
     */
    private void writeExcelToOutput1(OutputStream outputStream,
        List<CellMergeParam> cellMergeParams, String... titles) {
        List<List<Object>> writeList = new ArrayList<>();
        for (Object[] x : dataList) {
            if (x != null) {
                writeList.add(Arrays.asList(x));
            }
        }

        doWrite(writeList, outputStream, cellMergeParams, titles);
    }
    
    private void writeExcelToOutputWithoutTitles(OutputStream outputStream,
    		List<CellMergeParam> cellMergeParams, String... titles) {
    	List<List<Object>> writeList = new ArrayList<>();
    	for (Object[] x : dataList) {
    		if (x != null) {
    			writeList.add(Arrays.asList(x));
    		}
    	}
    	
    	doWriteWithoutTitles(writeList, outputStream, cellMergeParams, titles);
    }

    private void doWrite(List<List<Object>> writeList, OutputStream outputStream, List<CellMergeParam> cellMergeParams, String... titles) {
        ExcelWriter writer;
        if (outputStream instanceof ZipOutputStream) {
            // zip文件需要多次写入，xlsx写入一次后会关闭流，只能使用xls
            writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLS, true);
        } else {
            writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true);
        }
        // 写第一个sheet, sheet1  数据全是List<String> 无模型映射关系
        Sheet sheet1 = new Sheet(1, 0);
        // 设置表头
        if (titles != null && titles.length > 0) {
            sheet1.setHead(Arrays.stream(rowName).map(x -> {
                List<String> list = new ArrayList<>();
                list.addAll(Arrays.asList(titles));
                list.add(x);
                return list;
            }).collect(Collectors.toList()));
        }else{
            sheet1.setHead(Arrays.stream(rowName).map(x -> {
                List<String> list = new ArrayList<>();
                list.add(x);
                return list;
            }).collect(Collectors.toList()));
        }

        sheet1.setSheetName(title);
        Font heardfont=new Font();
        heardfont.setFontHeightInPoints((short) 12);
        heardfont.setBold(true);

        Font contentfont=new Font();
        contentfont.setFontHeightInPoints((short) 10);
        contentfont.setBold(false);

        TableStyle tableStyle = new TableStyle();
        tableStyle.setTableHeadFont(heardfont);
//        tableStyle.setTableHeadBackGroundColor(IndexedColors.WHITE);
//        tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
        tableStyle.setTableContentFont(contentfont);
        sheet1.setTableStyle(tableStyle);
        writer.write1(writeList, sheet1);
        cellMerge(cellMergeParams, writer);
        writer.finish();
    }
    
    private void doWriteWithoutTitles(List<List<Object>> writeList, OutputStream outputStream, 
    		List<CellMergeParam> cellMergeParams, String... titles) {
    	ExcelWriter writer;
    	log.info("doWriteWithoutTitles {}",titles);
    	if (outputStream instanceof ZipOutputStream) {
    		// zip文件需要多次写入，xlsx写入一次后会关闭流，只能使用xls
    		writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLS, true);
    	} else {
    		writer = new ExcelWriter(outputStream, ExcelTypeEnum.XLSX, true);
    	}
    	// 写第一个sheet, sheet1  数据全是List<String> 无模型映射关系
    	Sheet sheet1 = new Sheet(1, 0);
    	// 设置表头
    	rowName = (String[]) writeList.get(0).toArray();
    	List<Object> rowName2 = writeList.get(1);
    	List<List<String>> heads = new ArrayList<List<String>>();
    	for(int i =0;i<rowName.length;i++) {
    		List<String> head = new ArrayList<String>();
    		head.add(title);
    		head.add(rowName[i]);
    		head.add((String)rowName2.get(i));
    		heads.add(head);
    	}
    	sheet1.setHead(heads);
    	/**
        if (titles != null && titles.length > 0) {
            sheet1.setHead(Arrays.stream(rowName).map(x -> {
                List<String> list = new ArrayList<>();
                list.addAll(Arrays.asList(titles));
                list.add(x);
                return list;
            }).collect(Collectors.toList()));
        }else{
            sheet1.setHead(Arrays.stream(rowName).map(x -> {
                List<String> list = new ArrayList<>();
                list.add(x);
                return list;
            }).collect(Collectors.toList()));
        }
        */
    	
    	writeList = writeList.subList(2, writeList.size());
    	sheet1.setSheetName(title);
    	Font heardfont=new Font();
    	heardfont.setFontHeightInPoints((short) 12);
    	heardfont.setBold(true);
    	
    	Font contentfont=new Font();
    	contentfont.setFontHeightInPoints((short) 10);
    	contentfont.setBold(false);
    	
    	TableStyle tableStyle = new TableStyle();
    	tableStyle.setTableHeadFont(heardfont);
    	tableStyle.setTableHeadBackGroundColor(IndexedColors.WHITE);
    	tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
    	tableStyle.setTableContentFont(contentfont);
    	sheet1.setTableStyle(tableStyle);
    	writer.write1(writeList, sheet1);
    	cellMerge(cellMergeParams, writer);
    	writer.finish();
    }

    /**
     * 合并单元格
     *
     * @author wangyong
     * @param cellMergeParams
     * @param writer
     */
    private void cellMerge(List<CellMergeParam> cellMergeParams, ExcelWriter writer) {
        if (CollectionUtils.isEmpty(cellMergeParams)) {
            return;
        }
        for (CellMergeParam mergeParam : cellMergeParams) {
            writer.merge(mergeParam.getFirstRow(), mergeParam.getLastRow(),
                mergeParam.getFirstCol(), mergeParam.getLastCol());
        }
    }

    private void setHttpResponse(HttpServletResponse response) throws UnsupportedEncodingException {
        Format format = new SimpleDateFormat("yyyyMMdd");
        String fileName = "Excel-" + format.format(new Date()) + title;
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xlsx");
        response.setContentType("application/x-msdownload");
    }


}
